/**
 * @file online_manager.hpp
 * @brief 管理在线用户
 * 在线用户指的是进入游戏大厅和进入游戏房间的用户。
 * - 进入游戏大厅页面的用户会与服务器建立WebSocket长连接，一旦用户从游戏大厅页面跳转到游戏房间页面，
 *   用户持有的WebSocket连接会断开，需要在游戏房间页面与服务器重新建立连接。
 * 如何进行管理？
 * - 将【用户与服务器建立的WebSocket长连接】与【uid】进行关联起来。
 * - 用户能够通过连接获取到存储在数据库中的用户信息。
 * - 通过判断用户连接是否仍在在线用户管理模块中确认用户是否在线。
 */

#include "data_manager.hpp"
#include <unordered_map>
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>

using asio_wssvr_t = websocketpp::server<websocketpp::config::asio>;

class online_manager {
public:
    /**
     * @brief 当用户进入游戏大厅页面时，在游戏大厅中增加uid与连接的映射关系。
     * @param uid 用户的唯一标识符。
     * @param conn 用户与服务器的WebSocket连接指针。
     */
    void enter_game_hall(uint32_t uid, const asio_wssvr_t::connection_ptr &conn) {
        std::unique_lock<std::mutex> lock(_mutex);
        _game_hall.emplace(uid, conn);
    }

    /**
     * @brief 当用户退出游戏大厅时，从游戏大厅中删除uid与连接的映射关系。
     * @param uid 用户的唯一标识符。
     * @param conn 用户与服务器的WebSocket连接指针。
     */
    void exit_game_hall(uint32_t uid, const asio_wssvr_t::connection_ptr &conn) {
        std::unique_lock<std::mutex> lock(_mutex);
        _game_hall.erase(uid);
    }

    /**
     * @brief 当用户进入游戏房间页面时，在游戏房间中增加uid与连接的映射关系。
     * @param uid 用户的唯一标识符。
     * @param conn 用户与服务器的WebSocket连接指针。
     */
    void enter_game_room(uint32_t uid, const asio_wssvr_t::connection_ptr &conn) {
        std::unique_lock<std::mutex> lock(_mutex);
        _game_room.emplace(uid, conn);
    }

    /**
     * @brief 当用户退出游戏房间时，从游戏房间中删除uid与连接的映射关系。
     * @param uid 用户的唯一标识符。
     * @param conn 用户与服务器的WebSocket连接指针。
     */
    void exit_game_room(uint32_t uid, const asio_wssvr_t::connection_ptr &conn) {
        std::unique_lock<std::mutex> lock(_mutex);
        _game_room.erase(uid);
    }

    /**
     * @brief 判断一个用户是否在游戏大厅。
     * @param uid 数据库中的用户ID。
     * @return 返回值为bool类型，值为true表示用户在游戏大厅，值为false表示用户不在游戏大厅。
     */
    bool is_in_game_hall(uint32_t uid) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _game_hall.find(uid);
        return it != _game_hall.end();
    }

    /**
     * @brief 判断一个用户是否在游戏房间。
     * @param uid 数据库中的用户ID。
     * @return 返回值为bool类型，值为true表示用户在游戏房间，值为false表示用户不在游戏房间。
     */
    bool is_in_game_room(uint32_t uid) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _game_room.find(uid);
        return it != _game_room.end();
    }

    /**
     * @brief 在游戏大厅中获取uid对应的用户连接。
     * @param uid 用户的唯一标识符。
     * @return 返回用户对应的WebSocket连接指针，如果不存在则返回空指针。
     */
    asio_wssvr_t::connection_ptr get_conn_from_game_hall(uint32_t uid) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _game_hall.find(uid);
        if (it == _game_hall.end()) {
            return asio_wssvr_t::connection_ptr(); // 返回空指针表示用户不在游戏大厅
        }
        return it->second; // 返回用户的连接指针
    }

    /**
     * @brief 在游戏房间中获取uid对应的用户连接。
     * @param uid 用户的唯一标识符。
     * @return 返回用户对应的WebSocket连接指针，如果不存在则返回空指针。
     */
    asio_wssvr_t::connection_ptr get_conn_from_game_room(uint32_t uid) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _game_room.find(uid);
        if (it == _game_room.end()) {
            return asio_wssvr_t::connection_ptr(); // 返回空指针表示用户不在游戏房间
        }
        return it->second; // 返回用户的连接指针
    }

private:
    std::mutex _mutex; // 保护在线用户数据结构的互斥锁
    std::unordered_map<uint32_t, asio_wssvr_t::connection_ptr> _game_hall;  // 游戏大厅的客户端连接与uid的映射表
    std::unordered_map<uint32_t, asio_wssvr_t::connection_ptr> _game_room;  // 游戏房间的客户端连接与uid的映射表
};
